package org.devgframwork.platform.support.error;

import org.devgframwork.platform.model.ResultModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;
import java.util.stream.Collectors;

@ControllerAdvice
@RestController
public class ErrorController {

    private final static Logger log = LoggerFactory.getLogger(ErrorController.class);

    @RequestMapping(value = {"/error/329"})
    public ResultModel page329(HttpServletRequest request) {
        return ResultModel.newFail(HttpStatusEnum.ERROR329.getCode(), HttpStatusEnum.ERROR329.getMessage());
    }

    @RequestMapping(value = {"/error/400"})
    public ResultModel page400(HttpServletRequest request) {
        return ResultModel.newFail(HttpStatusEnum.ERROR400.getCode(), HttpStatusEnum.ERROR400.getMessage());
    }

    @RequestMapping(value = {"/error/401"})
    public ResultModel page401(HttpServletRequest request) {
        return ResultModel.newFail(HttpStatusEnum.ERROR401.getCode(), HttpStatusEnum.ERROR401.getMessage());
    }

    @RequestMapping(value = {"/error/404"})
    public ResultModel page404(HttpServletRequest request) {
        return ResultModel.newFail(HttpStatusEnum.ERROR404.getCode(), HttpStatusEnum.ERROR404.getMessage());
    }

    @RequestMapping(value = {"/error/429"})
    public ResultModel page429(HttpServletRequest request) {
        return ResultModel.newFail(HttpStatusEnum.ERROR429.getCode(), HttpStatusEnum.ERROR429.getMessage());
    }

    @RequestMapping(value = {"/error/500"})
    public ResultModel page500(HttpServletRequest request) {
        return ResultModel.newFail(HttpStatusEnum.ERROR500.getCode(), HttpStatusEnum.ERROR500.getMessage());
    }

    @ExceptionHandler(value = Exception.class)
    public ResultModel errorHandler(HttpServletRequest request, Exception ex) {
        log.error(ex.toString(), ex);
        return ResultModel.newFail();
    }

    @ExceptionHandler(value = {BindException.class, ValidationException.class, MethodArgumentNotValidException.class})
    public ResultModel handleValidatedException(Exception e) {
//        BindingResult bindResult = ex.getBindingResult();
//        String message = bindResult.getFieldError().getDefaultMessage();
//        return ResultModel.newFail(message);
        String resp = null;
        if (e instanceof MethodArgumentNotValidException) {
            // BeanValidation exception
            MethodArgumentNotValidException ex = (MethodArgumentNotValidException) e;
            resp = ex.getBindingResult().getAllErrors().stream().map(ObjectError::getDefaultMessage).collect(Collectors.joining("; "));
        } else if (e instanceof ConstraintViolationException) {
            // BeanValidation GET simple param
            ConstraintViolationException ex = (ConstraintViolationException) e;
            resp = ex.getConstraintViolations().stream().map(ConstraintViolation::getMessage).collect(Collectors.joining("; "));
        } else if (e instanceof BindException) {
            // BeanValidation GET object param
            BindException ex = (BindException) e;
//            resp = ex.getAllErrors().stream().map(ObjectError::getDefaultMessage).collect(Collectors.joining("; "));
            resp = ex.getFieldError().getDefaultMessage();
        }
        return ResultModel.newFail(HttpStatusEnum.ERROR500.getCode(), resp);
    }

}
